Move OziExplorer into it's own module. Adds track/route read/write support for Ozi.
authoralexmot <alexmot@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Mon, 5 Jan 2004 15:47:33 +0000 (15:47 +0000)
committeralexmot <alexmot@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Mon, 5 Jan 2004 15:47:33 +0000 (15:47 +0000)
gpsbabel/Makefile
gpsbabel/internal_styles.c
gpsbabel/ozi.c [new file with mode: 0644]
gpsbabel/vecs.c

index b391a4bdbf070aea6a05aef42e7ffe1b868252da..40eb1dbe172410626c881933a4494bcdeaa21ed8 100644 (file)
@@ -18,7 +18,8 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o \
        gpsutil.o pcx.o cetus.o copilot.o gpspilot.o magnav.o \
        psp.o holux.o garmin.o tmpro.o tpg.o \
        xcsv.o gcdb.o tiger.o internal_styles.o easygps.o quovadis.o \
-       gpilots.o saroute.o navicache.o psitrex.o geoniche.o delgpl.o
+       gpilots.o saroute.o navicache.o psitrex.o geoniche.o delgpl.o \
+       ozi.o
 
 FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o reverse_route.o
 
@@ -211,5 +212,5 @@ jeeps/gpsutil.o: jeeps/gpsutil.c jeeps/gps.h jeeps/gpsport.h \
   jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \
   jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \
   jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h
-internal_styles.c: mkstyle.sh style/README.style style/arc.style style/csv.style style/custom.style style/dna.style style/fugawi.style style/gpsdrive.style style/gpsman.style style/mapconverter.style style/mxf.style style/nima.style style/ozi.style style/s_and_t.style style/tabsep.style style/xmap.style style/xmapwpt.style
+internal_styles.c: mkstyle.sh style/README.style style/arc.style style/csv.style style/custom.style style/dna.style style/fugawi.style style/gpsdrive.style style/gpsman.style style/mapconverter.style style/mxf.style style/nima.style style/s_and_t.style style/tabsep.style style/xmap.style style/xmapwpt.style
        ./mkstyle.sh > $@ || (rm -f $@ ; exit 1)
index 9bc065bfa1505db11ddfc20b3773adafd9aeba42..93accec7f3f9dbe32ad27c7883a24a52eeb64b89 100644 (file)
@@ -368,56 +368,6 @@ static char nima[] =
 "IFIELD        DESCRIPTION, \"\", \"%s\"               # FULL_NAME_ND\n"
 "IFIELD        IGNORE, \"\", \"%s\"            # MODIFY_DATE\n"
 ;
-static char ozi[] = 
-"# gpsbabel XCSV style file\n"
-"#\n"
-"# Format: Ozi Explorer\n"
-"# Author: Alex Mottram\n"
-"#   Date: 12/09/2002\n"
-"#\n"
-"# \n"
-"# As used in ozi.c\n"
-"# Modifications 9/18/2003 - Remove printf conversion constraints.\n"
-"#\n"
-
-"DESCRIPTION           OziExplorer Waypoint\n"
-"EXTENSION             ozi\n"
-"SHORTLEN              14\n"
-
-"#\n"
-"# FILE LAYOUT DEFINITIIONS:\n"
-"#\n"
-"FIELD_DELIMITER               COMMA\n"
-"RECORD_DELIMITER      NEWLINE\n"
-"BADCHARS              COMMA\n"
-
-"PROLOGUE      OziExplorer Waypoint File Version 1.1\n"
-"PROLOGUE      WGS 84\n"
-"PROLOGUE      Reserved 2\n"
-"PROLOGUE      Reserved 3\n"
-
-"#\n"
-"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n"
-"#\n"
-"IFIELD        INDEX, \"1\", \"%d\"\n"
-"IFIELD        SHORTNAME, \"\", \"%s\"\n"
-"IFIELD        LAT_DECIMAL, \"\", \"%.6f\"\n"
-"IFIELD        LON_DECIMAL, \"\", \"%.6f\"\n"
-"IFIELD        EXCEL_TIME, \"\", \"%.5f\"\n"
-"IFIELD        CONSTANT, \"0\", \"%s\"                 # icon \n"
-"IFIELD        CONSTANT, \"1\", \"%s\"                 # 1 \n"
-"IFIELD        CONSTANT, \"3\", \"%s\"                 # display format opts \n"
-"IFIELD        CONSTANT, \"0\", \"%s\"                 # foreground color \n"
-"IFIELD        CONSTANT, \"65535\", \"%s\"     # background color \n"
-"IFIELD        DESCRIPTION, \"\", \"%s\"\n"
-"IFIELD        CONSTANT, \"0\", \"%s\"                 # pointer direction \n"
-"IFIELD        CONSTANT, \"0\", \"%s\"                 # garmin display flags \n"
-"IFIELD        CONSTANT, \"0\", \"%s\"                 # proximity distance \n"
-"IFIELD        ALT_FEET, \"\", \"%.0f\"\n"
-"IFIELD        CONSTANT, \"6\", \"%s\"                 # waypt name text size \n"
-"IFIELD        CONSTANT, \"0\", \"%s\"                 # bold checkbox \n"
-"IFIELD        CONSTANT, \"17\", \"%s\"                # symbol size \n"
-;
 static char s_and_t[] = 
 "# gpsbabel XCSV style file\n"
 "#\n"
@@ -567,4 +517,4 @@ static char xmapwpt[] =
 "IFIELD        DESCRIPTION, \"\", \"%-.78s\"\n"
 ;
 #include "defs.h"
-style_vecs_t style_list[] = {{ "xmapwpt", xmapwpt } , { "xmap", xmap } , { "tabsep", tabsep } , { "s_and_t", s_and_t } , { "ozi", ozi } , { "nima", nima } , { "mxf", mxf } , { "mapconverter", mapconverter } , { "gpsman", gpsman } , { "gpsdrive", gpsdrive } , { "fugawi", fugawi } , { "dna", dna } , { "custom", custom } , { "csv", csv } , { "arc", arc } ,  {0,0}};
+style_vecs_t style_list[] = {{ "xmapwpt", xmapwpt } , { "xmap", xmap } , { "tabsep", tabsep } , { "s_and_t", s_and_t } , { "nima", nima } , { "mxf", mxf } , { "mapconverter", mapconverter } , { "gpsman", gpsman } , { "gpsdrive", gpsdrive } , { "fugawi", fugawi } , { "dna", dna } , { "custom", custom } , { "csv", csv } , { "arc", arc } ,  {0,0}};
diff --git a/gpsbabel/ozi.c b/gpsbabel/ozi.c
new file mode 100644 (file)
index 0000000..e224a56
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+    OziExplorer Waypoints/Tracks/Routes
+    Comma Delimited 
+
+    As described in OziExplorer Help File
+
+    Copyright (C) 2002 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+#include "csv_util.h"
+#include <ctype.h>
+#include <math.h>                /* for floor */
+
+#define MYNAME        "OZI"
+
+
+static FILE *file_in;
+static FILE *file_out;
+static void *mkshort_handle;
+static route_head *trk_head;
+static route_head *rte_head;
+
+static int route_out_count;
+static int route_wpt_count;
+
+static char *snlenopt;
+static char *snwhiteopt;
+static char *snupperopt;
+static char *snuniqueopt;
+
+static char *ozi_wpt_header = "OziExplorer Waypoint File Version 1.1\n"
+                              "WGS 84\n" 
+                              "Reserved 2\n" 
+                              "Reserved 3\n";
+
+static char *ozi_trk_header = "OziExplorer Track Point File Version 2.1\n"
+                              "WGS 84\n"
+                              "Altitude is in Feet\n"
+                              "Reserved 3\n" 
+                              "0,2,255,ComplimentsOfGPSBabel,0,0,2,8421376\n"
+                              "0\n";
+
+static char *ozi_route_header = "OziExplorer Route File Version 1.0\n"
+                                "WGS 84\n" 
+                                "Reserved 1\n" 
+                                "Reserved 2\n";
+
+static
+arglist_t ozi_args[] = {
+       {"snlen", &snlenopt, "Max synthesized shortname length",
+               ARGTYPE_INT},
+       {"snwhite", &snwhiteopt, "(0/1) Allow whitespace synth. shortnames",
+               ARGTYPE_BOOL},
+       {"snupper", &snupperopt, "(0/1) UPPERCASE synth. shortnames",
+               ARGTYPE_BOOL},
+       {"snunique", &snuniqueopt, "(0/1) Make synth. shortnames unique",
+               ARGTYPE_BOOL},
+       {0, 0, 0, 0}
+};
+
+static void 
+ozi_track_hdr(const route_head * rte)
+{
+    /* prologue at TOF only. */
+    if (route_out_count == 0) 
+        fprintf(file_out, ozi_trk_header);
+
+    route_out_count++;
+}
+
+static void 
+ozi_track_disp(const waypoint * waypointp)
+{
+    double alt_feet;
+    double ozi_time;
+
+    ozi_time = (waypointp->creation_time / 86400.0) + 25569.0;
+
+    if (waypointp->altitude == unknown_alt) {
+        alt_feet = -777;
+    } else {
+        alt_feet = (waypointp->altitude * 3.2808);
+    }
+
+    fprintf(file_out, "%.6f,%.6f,0,%.0f,%.5f,,\n",
+            waypointp->latitude, waypointp->longitude, alt_feet, ozi_time);
+}
+
+static void
+ozi_track_tlr(const route_head * rte)
+{
+}
+
+static void 
+ozi_track_pr()
+{
+    route_disp_all(ozi_track_hdr, ozi_track_tlr, ozi_track_disp);
+}
+
+static void
+ozi_route_hdr(const route_head * rte)
+{
+    /* prologue on 1st pass only */
+    if (route_out_count == 0) {
+        fprintf(file_out, ozi_route_header);
+    }
+
+    route_out_count++;
+    route_wpt_count = 0;
+
+    /*
+     * Route Record 
+     * Field 1 : R - indicating route details
+     * Field 2 : Number - this is the location in the array, must be unique, usually start at 0 for Garmins 1 for other and increment.
+     * Field 3 : Name - the waypoint name, use the correct length name to suit the GPS type.
+     * Field 4 : Description.
+     * Field 5 : Route Color as displayed on map (RGB).
+     *
+     * R, 0,R0 ,,255 
+     * R, 1, ICP GALHETA,, 16711680 
+     */
+     
+     fprintf(file_out, "R,%d,%s,%s,\n", 
+         route_out_count, 
+         rte->rte_name ? rte->rte_name : "", 
+         rte->rte_desc ? rte->rte_desc : "");
+
+}
+
+static void
+ozi_route_disp(const waypoint * waypointp)
+{
+    double alt_feet;
+    double ozi_time;
+
+    route_wpt_count++;
+
+    ozi_time = (waypointp->creation_time / 86400.0) + 25569.0;
+
+    if (waypointp->altitude == unknown_alt) {
+        alt_feet = -777;
+    } else {
+        alt_feet = (waypointp->altitude * 3.2808);
+    }
+
+/*
+ *   Field 1 : W - indicating route waypoint details.
+ *   Field 2 : Route Number - location in array of routes
+ *   Field 3 : Number - this is the location in the array of route waypoints, this field is now ignored.
+ *   Field 4 : Wp Number - this is the number of the waypoint (the Wp number within the GPS for lowrances)
+ *   Field 5 : Name - the waypoint name, use the correct length name to suit the GPS type.
+ *   Field 6 : Latitude - decimal degrees.
+ *   Field 7 : Longitude - decimal degrees.
+ *   Field 8 : Date - see Date Format below, if blank a preset date will be used
+ *   Field 9 : Symbol - 0 to number of symbols in GPS
+ *   Field 10 : Status - always set to 1
+ *   Field 11 : Map Display Format
+ *   Field 12 : Foreground Color (RGB value)
+ *   Field 13 : Background Color (RGB value)
+ *   Field 14 : Description (max 40), no commas
+ *   Field 15 : Pointer Direction
+ *   Field 16 : Garmin Display Format
+ *
+ * W,1,7,7,007,-25.581670,-48.316660,36564.54196,10,1,4,0,65535,TR ILHA GALHETA,0,0 
+ */
+
+    fprintf(file_out, "W,%d,%d,,%s,%.6f,%.6f,%.5f,0,1,3,0,65535,%s,0,0\n", 
+            route_out_count,
+            route_wpt_count,
+            waypointp->shortname ? waypointp->shortname : "",
+            waypointp->latitude,
+            waypointp->longitude,
+            ozi_time,
+            waypointp->description ? waypointp->description : "");
+
+
+}
+
+static void
+ozi_route_tlr(const route_head * rte)
+{
+}
+
+static void 
+ozi_route_pr()
+{
+    route_disp_all(ozi_route_hdr, ozi_route_tlr, ozi_route_disp);
+}
+
+
+static void
+rd_init(const char *fname)
+{
+    file_in = fopen(fname, "r");
+
+    if (file_in == NULL) {
+        fatal(MYNAME ": Cannot open %s for reading\n", fname);
+    }
+
+    mkshort_handle = mkshort_new_handle();
+
+    switch (global_opts.objective) {
+    case trkdata:
+        trk_head = route_head_alloc();
+        route_add_head(trk_head);
+        break;
+    case rtedata:
+        break;
+    case wptdata:
+        break;
+    default:
+        break;
+
+    }
+}
+
+static void
+rd_deinit(void)
+{
+    fclose(file_in);
+    mkshort_del_handle(mkshort_handle);
+}
+
+static void
+wr_init(const char *fname)
+{
+    file_out = fopen(fname, "w");
+
+    if (file_out == NULL) {
+        fatal(MYNAME ": Cannot open %s for writing\n", fname);
+    }
+
+    mkshort_handle = mkshort_new_handle();
+
+    /* set mkshort options from the command line if applicable */
+    if (global_opts.synthesize_shortnames) {
+
+        if (snlenopt)
+            setshort_length(mkshort_handle, atoi(snlenopt));
+        else 
+            setshort_length(mkshort_handle, 32);
+
+        if (snwhiteopt)
+            setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt));
+
+        if (snupperopt)
+            setshort_mustupper(mkshort_handle, atoi(snupperopt));
+
+        if (snuniqueopt)
+            setshort_mustuniq(mkshort_handle, atoi(snuniqueopt));
+
+        setshort_badchars(mkshort_handle, "\",");
+    }
+
+}
+
+static void
+wr_deinit(void)
+{
+    fclose(file_out);
+    mkshort_del_handle(mkshort_handle);
+}
+
+static void
+ozi_parse_waypt(int field, char *str, waypoint * wpt_tmp)
+{
+    double alt;
+
+    switch (field) {
+    case 0:
+        /* sequence # */
+        break;
+    case 1:
+        /* waypoint name */
+        wpt_tmp->shortname = csv_stringtrim(str, "", 0);
+        break;
+    case 2:
+        /* degrees latitude */
+        wpt_tmp->latitude = atof(str);
+        break;
+    case 3:
+        /* degrees longitude */
+        wpt_tmp->longitude = atof(str);
+        break;
+    case 4:
+        /* DAYS since 1900 00:00:00 in days.days (5.5) */
+        wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0;
+        break;
+    case 5:
+        /* icons 0-xx */
+        break;
+    case 6:
+        /* unknown - always 1 */
+        break;
+    case 7:
+        /* display format options 0-8 */
+        break;
+    case 8:
+        /* foreground color (0=black) */
+        break;
+    case 9:
+        /* background color (65535=yellow) */
+        break;
+    case 10:
+        /* Description */
+        wpt_tmp->description = csv_stringtrim(str, "", 0);
+        break;
+    case 11:
+        /* pointer direction 0,1,2,3 bottom,top,left,right */
+        break;
+    case 12:
+        /* garmin gps display flags (0-name w/sym, 1-sym only, 2-comment w/symbol */
+        break;
+    case 13:
+        /* proximity distance - meters */
+        break;
+    case 14:
+        /* altitude in feet */
+        alt = atof(str);
+        if (alt == -777) {
+            wpt_tmp->altitude = unknown_alt;
+        } else {
+            wpt_tmp->altitude = alt * .3048;
+        }
+        break;
+    case 15:
+        /* waypoint text name size */
+        break;
+    case 16:
+        /* bold checkbox (1=bold, default 0) */
+        break;
+    case 17:
+        /* symbol size - 17 default */
+        break;
+        /* 
+         * Fields 18-23 were added around version 3.90.4g of
+         * Ozi, but aren't documented.   We silently ignore 
+         * these or any additional fields we don't need.
+         */
+    default:
+        break;
+    }
+}
+
+static void
+ozi_parse_track(int field, char *str, waypoint * wpt_tmp)
+{
+    double alt;
+
+    switch (field) {
+    case 0:
+        /* latitude */
+        wpt_tmp->latitude = atof(str);
+        break;
+    case 1:
+        /* longitude */
+        wpt_tmp->longitude = atof(str);
+        break;
+    case 2:
+        /* ignore */
+        break;
+    case 3:
+        /* altitude in feet */
+        alt = atof(str);
+        if (alt == -777) {
+            wpt_tmp->altitude = unknown_alt;
+        } else {
+            wpt_tmp->altitude = alt * .3048;
+        }
+        break;
+    case 4:
+        /* DAYS since 1900 00:00:00 in days.days (5.5) */
+        wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0;
+        break;
+    default:
+        break;
+    }
+}
+
+static void
+ozi_parse_routepoint(int field, char *str, waypoint * wpt_tmp)
+{
+
+    switch (field) {
+    case 0:
+        /* W */
+        break;
+    case 1:
+        /* route # */
+        break;
+    case 2:
+        /* waypoint # -- ignored by ozi */
+        break;
+    case 3:
+        /* waypoint # */
+        break;
+    case 4:
+        /* waypoint name */
+        wpt_tmp->shortname = csv_stringclean(str, ",");
+        break;
+    case 5:
+        /* latitude */
+        wpt_tmp->latitude = atof(str);
+        break;
+    case 6:
+        /* longitude */
+        wpt_tmp->longitude = atof(str);
+        break;
+    case 7:
+        /* DAYS since 1900 00:00:00 in days.days (5.5) */
+        wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0;
+        break;
+    default:
+        break;
+    }
+}
+
+static void
+ozi_parse_routeheader(int field, char *str, waypoint * wpt_tmp)
+{
+
+    switch (field) {
+    case 0:
+        /* R */
+        rte_head = route_head_alloc();
+        route_add_head(rte_head);
+        break;
+    case 1:
+        /* route # */
+        rte_head->rte_num = atoi(str);
+        break;
+    case 2:
+        /* route name */
+        rte_head->rte_name = csv_stringclean(str, ",");
+        break;
+    case 3:
+        /* route description */
+        rte_head->rte_desc = csv_stringclean(str, ",");
+        break;
+    case 4:
+        /* route color */
+        break;
+    default:
+        break;
+    }
+}
+
+static void
+data_read(void)
+{
+    char buff[1024];
+    char *s;
+    waypoint *wpt_tmp;
+    int i;
+    int linecount = 0;
+
+    do {
+        linecount++;
+        memset(buff, '\0', sizeof(buff));
+        fgets(buff, sizeof(buff), file_in);
+
+        if ((strlen(buff)) && (strstr(buff, ",") != NULL)) {
+
+            wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1);
+
+            /* data delimited by commas, possibly enclosed in quotes.  */
+            s = buff;
+            s = csv_lineparse(s, ",", "", linecount);
+
+            i = 0;
+            while (s) {
+                switch (global_opts.objective) {
+                case trkdata:
+                    ozi_parse_track(i, s, wpt_tmp);
+                    break;
+                case rtedata:
+                    if (buff[0] == 'R') {
+                        ozi_parse_routeheader(i, s, wpt_tmp);
+                    } else {
+                        ozi_parse_routepoint(i, s, wpt_tmp);
+                    }
+
+                    break;
+                case wptdata:
+                    ozi_parse_waypt(i, s, wpt_tmp);
+                    break;
+                }
+                i++;
+                s = csv_lineparse(NULL, ",", "", linecount);
+            }
+
+            switch (global_opts.objective) {
+            case trkdata:
+                if (linecount > 6) /* skipping over file header */
+                    route_add_wpt(trk_head, wpt_tmp);
+                else
+                    waypt_free(wpt_tmp);
+                break;
+            case rtedata:
+                if (linecount > 5) /* skipping over file header */
+                    route_add_wpt(rte_head, wpt_tmp);
+                else
+                    waypt_free(wpt_tmp);
+                break;
+            case wptdata:
+                if (linecount > 4)  /* skipping over file header */
+                    waypt_add(wpt_tmp);
+                else
+                    waypt_free(wpt_tmp);
+                break;
+            }
+
+        } else {
+            /* empty line */
+        }
+
+    } while (!feof(file_in));
+}
+
+static void
+ozi_waypt_pr(const waypoint * wpt)
+{
+    static int index = 0;
+    double alt_feet;
+    double ozi_time;
+    char *description;
+    char *shortname;
+
+    ozi_time = (wpt->creation_time / 86400.0) + 25569.0;
+
+    if (wpt->altitude == unknown_alt) {
+        alt_feet = -777;
+    } else {
+        alt_feet = (wpt->altitude * 3.2808);
+    }
+
+    if ((!wpt->shortname) || (global_opts.synthesize_shortnames)) {
+        if (wpt->description) {
+            if (global_opts.synthesize_shortnames)
+                shortname = mkshort(mkshort_handle, wpt->description);
+            else
+                shortname = csv_stringclean(wpt->description, ",");
+        } else {
+            /* no description available */
+            shortname = xstrdup("");
+        }
+    } else {
+        shortname = csv_stringclean(wpt->shortname, ",");
+    }
+
+    if (!wpt->description) {
+        if (shortname) {
+            description = csv_stringclean(shortname, ",");
+        } else {
+            description = xstrdup("");
+        }
+    } else {
+        description = csv_stringclean(wpt->description, ",");
+    }
+
+    index++;
+
+    fprintf(file_out,
+            "%d,%s,%.6f,%.6f,%.5f,%d,%d,%d,%d,%d,%s,%d,%d,%d,%.0f,%d,%d,%d\n",
+            index, shortname, wpt->latitude, wpt->longitude, ozi_time, 0,
+            1, 3, 0, 65535, description, 0, 0, 0, alt_feet, 6, 0, 17);
+
+    free(description);
+    free(shortname);
+
+}
+
+static void
+data_write(void)
+{
+
+    switch (global_opts.objective) {
+    case trkdata:
+        ozi_track_pr();
+        break;
+    case rtedata:
+        route_out_count = 0;
+        ozi_route_pr();
+        break;
+    case wptdata:
+        fprintf(file_out, ozi_wpt_header);
+        waypt_disp_all(ozi_waypt_pr);
+        break;
+    default:
+        break;
+    }
+}
+
+ff_vecs_t ozi_vecs = {
+    rd_init,
+    wr_init,
+    rd_deinit,
+    wr_deinit,
+    data_read,
+    data_write,
+    ozi_args
+};
index 5f56728b90a66dceb7c631c3af10b84bf0ea3561..4a828dd3f5e54529cf049e06290353aadafc7310 100644 (file)
@@ -57,6 +57,7 @@ extern ff_vecs_t navicache_vecs;
 extern ff_vecs_t psit_vecs;             /* MRCB */
 extern ff_vecs_t geoniche_vecs;
 extern ff_vecs_t gpl_vecs;
+extern ff_vecs_t ozi_vecs;
 
 static
 vecs_t vec_list[] = {
@@ -223,6 +224,12 @@ vecs_t vec_list[] = {
                "Delorme GPL",
                NULL
        },
+       {
+               &ozi_vecs,
+               "ozi",
+               "OziExplorer",
+               NULL
+       },
        {
                NULL,
                NULL,